use axum::{response::IntoResponse, Json};

use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

// 定义trait和结构体
pub trait ResponseSuccessWithOutData<T> {
    fn success() -> Response<T>;
}
pub trait ResponseSuccessWithData<T> {
    fn success(data: T) -> Response<T>;
}
pub trait ResponseFailed<T> {
    fn failed(code: u16, message: String) -> Response<T>;
}

pub trait ResponseSuccessWithOption<T> {
    fn success(data: Option<T>) -> Response<Option<T>>;
}

#[derive(Debug, Serialize, Clone, Deserialize, ToSchema)]
pub struct Response<T> {
    #[schema(example = json!("code"))]
    pub code: u16,
    #[schema(example = json!("message"))]
    pub message: String,
    #[schema(example = json!("data"))]
    pub data: Option<T>, // 保持字段类型为Option<T>
}

impl<T> ResponseFailed<T> for Response<T>
where
    T: Serialize + for<'de> Deserialize<'de>,
{
    fn failed(code: u16, message: String) -> Response<T> {
        Response {
            code,
            message,
            data: None,
        }
    }
}

impl<T> ResponseSuccessWithOutData<T> for Response<T>
where
    T: Serialize + for<'de> Deserialize<'de>,
{
    fn success() -> Response<T> {
        Response {
            code: 200,
            message: "success".to_string(),
            data: None,
        }
    }
}

impl<T> ResponseSuccessWithData<T> for Response<T>
where
    T: Serialize + for<'de> Deserialize<'de>,
{
    fn success(data: T) -> Response<T> {
        Response {
            code: 200,
            message: "success".to_string(),
            data: Some(data),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_response_failed() {
        let response = Response::<String>::failed(400, "Bad Request".to_string());
        assert_eq!(response.code, 400);
        assert_eq!(response.message, "Bad Request");
        assert_eq!(response.data, None);
    }

    #[test]
    fn test_response_success() {
        let foo_result = <Response<String> as ResponseSuccessWithOutData<String>>::success();
        assert_eq!(foo_result.code, 200);
        assert_eq!(foo_result.message, "success");
        assert_eq!(foo_result.data, None);
    }

    #[test]
    fn test_response_success_with_data() {
        let foo_result =
            <Response<String> as ResponseSuccessWithData<String>>::success("bar".to_string());
        assert_eq!(foo_result.code, 200);
        assert_eq!(foo_result.message, "success");
        assert_eq!(foo_result.data, Some("bar".to_string()));
    }
}

impl<T> IntoResponse for Response<T>
where
    T: Serialize + for<'de> Deserialize<'de>,
{
    fn into_response(self) -> axum::response::Response {
        Json(self).into_response()
    }
}
